home *** CD-ROM | disk | FTP | other *** search
/ IRIS Performer 2.2 Friends Demo / SGI IRIS Performer 2.2 Friends Demo.iso / friends / openworlds / tix / ComboBox.tcl < prev    next >
Text File  |  1997-11-22  |  25KB  |  1,054 lines

  1. # tixCombobox --
  2. #
  3. #    A combobox widget is basically a listbox widget with an entry
  4. #    widget.
  5. #
  6. # Subwidgets
  7. #
  8. #    button, cross, entry, listbox, shell, slistbox, tick
  9. #
  10. # Item shown in the entry:
  11. #    By default it will be the first item inserted into the list.
  12. #    This can be changed by "config -value" or "pick" a different
  13. #    value.
  14. #
  15. # Widget Commands
  16. #    align   -- align the combobox to either right or left
  17. #    insert  -- insert into the listbox
  18. #    pick    -- select a different item in the list to show in the entry
  19.  
  20. tixWidgetClass tixComboBox {
  21.     -classname TixComboBox
  22.     -superclass tixLabelWidget
  23.     -method {
  24.     addhistory align appendhistory invoke insert pick popdown
  25.     }
  26.     -flag {
  27.     -anchor -arrowbitmap -browsecmd -command -crossbitmap
  28.     -disablecallback -disabledforeground -dropdown -editable
  29.     -fancy -grab -histlimit -historylimit -history -listcmd  -listwidth
  30.     -prunehistory -selection -selectmode -state -tickbitmap -validatecmd
  31.     -value -variable
  32.     }
  33.     -static {
  34.     -fancy
  35.     }
  36.     -forcecall {
  37.     -variable -selectmode -state
  38.     }
  39.     -configspec {
  40.     {-arrowbitmap arrowBitmap ArrowBitmap [tix getbitmap cbxarrow]}
  41.     {-anchor anchor Anchor w}
  42.     {-browsecmd browseCmd BrowseCmd {}}
  43.         {-command command Command {}}
  44.     {-crossbitmap crossBitmap CrossBitmap [tix getbitmap cross]}
  45.     {-disablecallback disableCallback DisableCallback false tixVerifyBoolean}
  46.     {-disabledforeground disabledForeground DisabledForeground #606060}
  47.     {-dropdown dropDown DropDown true tixVerifyBoolean}
  48.     {-editable editable Editable false tixVerifyBoolean}
  49.     {-fancy fancy Fancy false tixVerifyBoolean}
  50.     {-grab grab Grab global}
  51.     {-listcmd listCmd ListCmd {}}
  52.     {-listwidth listWidth ListWidth {}}
  53.     {-historylimit historyLimit HistoryLimit {}}
  54.     {-history history History false tixVerifyBoolean}
  55.     {-prunehistory pruneHistory PruneHistory true tixVerifyBoolean}
  56.     {-selectmode selectMode SelectMode browse}
  57.     {-selection selection Selection {}}
  58.         {-state state State normal}
  59.     {-validatecmd validateCmd ValidateCmd {}}
  60.     {-value value Value ""}
  61.     {-variable variable Variable {}}
  62.     {-tickbitmap tickBitmap TickBitmap [tix getbitmap tick]}
  63.     }
  64.     -alias {
  65.     {-histlimit -historylimit}
  66.     }
  67.     -default {
  68.     {*Entry.relief                sunken}
  69.     {*TixScrolledListBox.scrollbar        auto}
  70.     {*Listbox.exportSelection        false}
  71.     {*Listbox.takeFocus            false}
  72.     {*shell.borderWidth            2}
  73.     {*shell.relief                raised}
  74.     {*shell.cursor                arrow}
  75.     {*Button.anchor                c}
  76.     {*Button.borderWidth            1}
  77.     {*Button.highlightThickness        0}
  78.     {*Button.padX                0}
  79.     {*Button.padY                0}
  80.     {*tick.width                18}
  81.     {*tick.height                18}
  82.     {*cross.width                18}
  83.     {*cross.height                18}
  84.     {*arrow.anchor                c}
  85.     {*arrow.width                15}
  86.     {*arrow.height                18}
  87.     {*Entry.background            #c3c3c3}
  88.     {*Label.font                   -Adobe-Helvetica-Bold-R-Normal--*-120-*}
  89.     }
  90. }
  91.  
  92. proc tixComboBox::InitWidgetRec {w} {
  93.     upvar #0 $w data
  94.  
  95.     tixChainMethod $w InitWidgetRec
  96.  
  97.     set data(popped)      0
  98.     set data(curIndex)    {}
  99.     set data(fakeBrowse)  0
  100.     set data(varInited)      0
  101.     if {$data(-history)} {
  102.         set data(-editable) 1
  103.     }
  104. }
  105.  
  106. proc tixComboBox::ConstructFramedWidget {w frame} {
  107.     upvar #0 $w data
  108.  
  109.     tixChainMethod $w ConstructFramedWidget $frame
  110.  
  111.     if {$data(-dropdown)} {
  112.     tixComboBox::ConstructEntryFrame $w $frame
  113.     tixComboBox::ConstructListShell $w
  114.     } else {
  115.     set f1 [frame $frame.f1]
  116.     set f2 [frame $frame.f2]
  117.  
  118.     tixComboBox::ConstructEntryFrame $w $f1
  119.     tixComboBox::ConstructListFrame  $w $f2
  120.     pack $f1 -side top -pady 2 -fill x
  121.     pack $f2 -side top -pady 2 -fill both -expand yes
  122.     }
  123. }
  124.  
  125. proc tixComboBox::ConstructEntryFrame {w frame} {
  126.     upvar #0 $w data
  127.  
  128.     # (1) The entry
  129.     #
  130.     set data(w:entry) [entry $frame.entry -textvariable $w::combo]
  131.     global $w::combo
  132.     trace variable $w::combo w "tixComboBox::TraceEntryVar $w"
  133.  
  134.     if {!$data(-editable)} {
  135.     set bg [$w cget -bg]
  136.     $data(w:entry) config -bg $bg -state disabled -takefocus 1
  137.     }
  138.  
  139.     # This is used during "config-state"
  140.     #
  141.     set data(entryfg) [$data(w:entry) cget -fg]
  142.  
  143.     # (2) The dropdown button, not necessary when not in dropdown mode
  144.     #
  145.     set data(w:arrow) [button $frame.arrow -bitmap $data(-arrowbitmap)]
  146.     if {!$data(-dropdown)} {
  147.     set xframe [frame $frame.xframe -width 19]
  148.     }
  149.  
  150.     # (3) The fancy tick and cross buttons
  151.     #
  152.     if {$data(-fancy)} {
  153.     if {$data(-editable)} {
  154.            set data(w:cross)  [button $frame.cross -bitmap $data(-crossbitmap)]
  155.        set data(w:tick)   [button $frame.tick  -bitmap $data(-tickbitmap)]
  156.  
  157.        pack $frame.cross -side left -padx 1
  158.        pack $frame.tick  -side left -padx 1
  159.     } else {
  160.        set data(w:tick)   [button $frame.tick  -bitmap $data(-tickbitmap)]
  161.        pack $frame.tick  -side left -padx 1
  162.     }
  163.     }
  164.  
  165.     if {$data(-dropdown)} {
  166.     pack $data(w:arrow) -side right -padx 1
  167.     } else {
  168.     pack $xframe -side right -padx 1
  169.     }
  170.     pack $frame.entry -side right -fill x -expand yes -padx 1
  171. }
  172.  
  173. proc tixComboBox::ConstructListShell {w} {
  174.     upvar #0 $w data
  175.  
  176.     # Create the shell and the list
  177.     #------------------------------
  178.     set data(w:shell) [toplevel $w.shell -bd 2 -relief raised]
  179.     wm overrideredirect $data(w:shell) 1
  180.     wm withdraw $data(w:shell)
  181.  
  182.     set data(w:slistbox) [tixScrolledListBox $data(w:shell).slistbox \
  183.      -anchor $data(-anchor) \
  184.      -options {listbox.selectMode "browse"}]
  185.  
  186.     set data(w:listbox) [$data(w:slistbox) subwidget listbox]
  187.  
  188.     pack $data(w:slistbox) -expand yes -fill both
  189. }
  190.  
  191. proc tixComboBox::ConstructListFrame {w frame} {
  192.     upvar #0 $w data
  193.  
  194.     set data(w:slistbox) [tixScrolledListBox $frame.slistbox \
  195.               -anchor $data(-anchor)]
  196.  
  197.     set data(w:listbox) [$data(w:slistbox) subwidget listbox]
  198.  
  199.     pack $data(w:slistbox) -expand yes -fill both
  200. }
  201.  
  202. bind TixComboEntry <Up>        {
  203.     tixComboBox::EntDirKey [tixGetMegaWidget %W] up
  204.     tixComboBox::LbBrowse  [tixGetMegaWidget %W]
  205. }
  206. bind TixComboEntry <Down>    {
  207.     tixComboBox::EntDirKey [tixGetMegaWidget %W] down
  208.     tixComboBox::LbBrowse  [tixGetMegaWidget %W]
  209. }
  210. bind TixComboEntry <Prior>    {
  211.     tixComboBox::EntDirKey [tixGetMegaWidget %W] pageup
  212. }
  213. bind TixComboEntry <Next>    {
  214.     tixComboBox::EntDirKey [tixGetMegaWidget %W] pagedown
  215. }
  216. bind TixComboEntry <Double-1>    {
  217.     tixComboBox::EntDouble [tixGetMegaWidget %W]
  218. }
  219. bind TixComboEntry <Return>    {    
  220.     tixComboBox::EntInvoke [tixGetMegaWidget %W] 1
  221. }
  222. bind TixComboEntry <1>         {
  223.     tixComboBox::EntButton1 [tixGetMegaWidget %W]
  224. }
  225. bind TixComboEntry <KeyPress>    {
  226.     tixComboBox::EntKeyPress [tixGetMegaWidget %W]
  227. }
  228. bind TixComboEntry <Escape>     {
  229.     tixComboBox::EscKey [tixGetMegaWidget %W]
  230. }
  231.  
  232. # The class bindings for the TixComboBox
  233. #
  234. bind TixComboBox <Escape> {
  235.     tixComboBox::EscKey %W
  236. }
  237. bind TixComboBox <1> {
  238.     if {[set %W(-dropdown)]} {
  239.     tixComboBox::CalcelXX %W
  240.     }
  241. }
  242. bind TixComboBox <Configure> {
  243.     tixWidgetDoWhenIdle tixComboBox::align %W
  244. }
  245.  
  246. # Only the two "linear" detail_fields  are for tabbing (moving) among
  247. # widgets inside the same toplevel. Other detail_fields are sort
  248. # of irrelevant
  249. #
  250. bind TixComboBox <FocusOut>  {
  251.     if {"%d" == "NotifyNonlinear" || "%d" == "NotifyNonlinearVirtual"} {
  252.     tixComboBox::EntInvoke %W 0
  253.     }
  254. }
  255. bind TixComboBox <FocusIn>  {
  256.     focus [%W subwidget entry]
  257. }
  258.  
  259.  
  260. proc tixComboBox::SetBindings {w} {
  261.     upvar #0 $w data
  262.  
  263.     tixChainMethod $w SetBindings
  264.  
  265.  
  266.     # (1) Fix the bindings for the combobox
  267.     #
  268.     bindtags $w \
  269.     "$w TixComboBox [winfo toplevel $w] all"
  270.  
  271.     # (2) The entry subwidget
  272.     #
  273.     tixSetMegaWidget $data(w:entry) $w
  274.  
  275.     bindtags $data(w:entry) \
  276.        "$data(w:entry) Entry TixComboEntry [winfo toplevel $data(w:entry)] all"
  277.  
  278.     # (3) The listbox and slistbox
  279.     #
  280.  
  281.     $data(w:slistbox) config -browsecmd "tixComboBox::LbBrowse  $w"
  282.     $data(w:slistbox) config -command   "tixComboBox::LbCommand $w"
  283.     $data(w:listbox) config -takefocus 0
  284.     bind $data(w:listbox)  <Escape> "tixComboBox::EscKey $w"
  285.     bind $data(w:slistbox) <Escape> "tixComboBox::EscKey $w"
  286.  
  287.     if {$data(-dropdown)} {
  288.     bind $data(w:listbox)  <ButtonRelease-1> \
  289.       "tixComboBox::ButtonHack $w; tixComboBox::LbChoose $w %x %y"
  290.     }
  291.  
  292.     # (4) The buttons
  293.     #
  294.     if {$data(-dropdown)} {
  295.     $data(w:arrow) config -takefocus 0
  296.     bind $data(w:arrow) <1> "tixComboBox::BtnDown $w"
  297.     bind $data(w:arrow) <Escape> "tixComboBox::EscKey $w"
  298.  
  299.     bind $data(w:root) <ButtonRelease-1> "tixComboBox::ButtonHack $w"
  300.     }
  301.     if {$data(-fancy)} {
  302.     if {$data(-editable)} {
  303.         $data(w:cross) config -command "tixComboBox::ClearEntry $w" \
  304.         -takefocus 0
  305.     }
  306.        $data(w:tick) config -command "tixComboBox::EntInvoke $w 1" -takefocus 0
  307.     }
  308. }
  309.  
  310. #----------------------------------------------------------------------
  311. #                           CONFIG OPTIONS
  312. #----------------------------------------------------------------------
  313.  
  314. #proc tixComboBox::config-selectmode {w value} {
  315. #    upvar #0 $w data
  316. #
  317. #    if {$data(-dropdown) && $value != "browse"} {
  318. #    puts stderr "\"$value \" selectmode not allowed for dropdown ComboBox"
  319. #    return browse
  320. #    }
  321. #}
  322.  
  323. proc tixComboBox::config-state {w value} {
  324.     upvar #0 $w data
  325.     catch {if {[[$data(w:arrow) cget -state] == $value} {
  326.     return
  327.     }}
  328.  
  329.     catch {
  330.     catch {$data(w:label) config -state $value}
  331.     catch {$data(w:arrow) config -state $value}
  332.     catch {$data(w:tick)  config -state $value}
  333.     catch {$data(w:cross) config -state $value}
  334.     }    
  335.  
  336.     if {$value == "normal"} {
  337.     catch {
  338.         $data(w:label) config -fg [$data(w:arrow) cget -fg]
  339.     }
  340.  
  341.     if {$data(-editable)} {
  342.         $data(w:entry) config -fg $data(entryfg) -state normal
  343.     } else {
  344.         $data(w:entry) config -fg $data(entryfg)
  345.     }
  346.         $data(w:entry) config -takefocus 1
  347.     } else {
  348.     catch {
  349.         $data(w:label) config -fg [$data(w:arrow) cget -disabledforeground]
  350.     }
  351.     
  352.  
  353.     if {$data(-editable)} {
  354.        $data(w:entry) config -fg $data(-disabledforeground) -state disabled
  355.         } else {
  356.         $data(w:entry) config -fg $data(-disabledforeground) 
  357.     }
  358.         $data(w:entry) config -takefocus 0
  359.     }
  360. }
  361.  
  362. proc tixComboBox::config-value {w value} {
  363.     upvar #0 $w data
  364.  
  365.     tixComboBox::SetValue $w $value
  366.  
  367.     set data(-selection) $value
  368.     tixComboBox::ClearListboxSelection $w
  369. }
  370.  
  371. proc tixComboBox::config-variable {w arg} {
  372.     upvar #0 $w data
  373.  
  374.     if [tixVariable:ConfigVariable $w $arg] {
  375.        # The value of data(-value) is changed if tixVariable:ConfigVariable 
  376.        # returns true
  377.        set data(-selection) $data(-value)
  378.        tixComboBox::SetValue $w $data(-value) 1
  379.     }
  380.     catch {
  381.     unset data(varInited)
  382.     }
  383.     set data(-variable) $arg
  384. }
  385.  
  386. #----------------------------------------------------------------------
  387. #                     WIDGET COMMANDS
  388. #----------------------------------------------------------------------
  389. proc tixComboBox::align {w args} {
  390.     upvar #0 $w data
  391.  
  392.     if {$data(-anchor) == "e"} {
  393.     tixComboBox::EntryAlignEnd $w
  394.     }
  395. }
  396.  
  397. proc tixComboBox::addhistory {w value} {
  398.     upvar #0 $w data
  399.  
  400.     tixComboBox::insert $w 0 $value
  401.     $data(w:listbox) selection clear 0 end
  402.  
  403.     if {$data(-prunehistory)} {
  404.     # Prune from the end
  405.     # 
  406.     set max [$data(w:listbox) size]
  407.     if {$max <= 1} {
  408.         return
  409.     }
  410.     for {set i [expr $max -1]} {$i >= 1} {incr i -1} {
  411.         if {[$data(w:listbox) get $i] == $value} {
  412.         $data(w:listbox) delete $i
  413.         break
  414.         }
  415.     }
  416.     }
  417. }
  418.  
  419. proc tixComboBox::appendhistory {w value} {
  420.     upvar #0 $w data
  421.  
  422.     tixComboBox::insert $w end $value
  423.     $data(w:listbox) selection clear 0 end
  424.  
  425.     if {$data(-prunehistory)} {
  426.     # Prune from the end
  427.     # 
  428.     set max [$data(w:listbox) size]
  429.     if {$max <= 1} {
  430.         return
  431.     }
  432.     for {set i [expr $max -2]} {$i >= 0} {incr i -1} {
  433.         if {[$data(w:listbox) get $i] == $value} {
  434.         $data(w:listbox) delete $i
  435.         break
  436.         }
  437.     }
  438.     }
  439. }
  440.  
  441.  
  442. proc tixComboBox::insert {w index newitem} {
  443.     upvar #0 $w data
  444.  
  445.     $data(w:listbox) insert $index $newitem
  446.  
  447.     if {$data(-history) && $data(-historylimit) != {}} {
  448.     if {[$data(w:listbox) size]  == $data(-historylimit)} {
  449.         $data(w:listbox) delete 0
  450.     }
  451.     }
  452. }
  453.  
  454. proc tixComboBox::config-selection {w value} {
  455.     upvar #0 $w data
  456.  
  457.     tixComboBox::SetSelection $w $value
  458.     tixComboBox::ClearListboxSelection $w
  459. }
  460.  
  461. proc tixComboBox::pick {w index} {
  462.     upvar #0 $w data
  463.     
  464.     $data(w:listbox) activate $index
  465.     $data(w:listbox) selection clear 0 end
  466.     $data(w:listbox) selection set active
  467.     $data(w:listbox) see active
  468.     set text [$data(w:listbox) get $index]
  469.  
  470.     tixComboBox::SetValue $w $text
  471.  
  472.     set data(curIndex) $index
  473. }
  474.  
  475. proc tixComboBox::invoke {w} {
  476.     tixComboBox::EntInvoke $w 1
  477. }
  478.  
  479. #----------------------------------------------------------------------
  480. #                   MAINTAINING THE -VALUE
  481. #----------------------------------------------------------------------
  482. proc tixComboBox::SetValue {w newValue {noUpdate 0}} {
  483.     upvar #0 $w data
  484.  
  485.     if {$data(-validatecmd) != {}} {
  486.     set data(-value) [eval $data(-validatecmd) [list $newValue]]
  487.     } else {
  488.     set data(-value) $newValue
  489.     }
  490.  
  491.     if {! $noUpdate} {
  492.     tixVariable:UpdateVariable $w
  493.     }
  494.  
  495.     if {!$data(-editable)} {
  496.     $data(w:entry) delete 0 end
  497.     $data(w:entry) insert 0 $data(-value)
  498.     }
  499.  
  500.     if {!$data(-disablecallback) && $data(-command) != {}} {
  501.     if {![info exists data(varInited)]} {
  502.         eval $data(-command) [list $data(-value)]
  503.     }
  504.     }
  505.  
  506.     tixSetEntry $data(w:entry) $data(-value)
  507.     set data(-selection) $data(-value)
  508.  
  509.     # Clear the selection
  510.     #
  511.     $data(w:entry) selection clear
  512.  
  513.     if {$data(-anchor) == "e"} {
  514.     tixComboBox::EntryAlignEnd $w
  515.     }
  516. }
  517.  
  518. proc tixComboBox::SetSelection {w value {markSel 1}} {
  519.     upvar #0 $w data
  520.  
  521.     tixSetEntry $data(w:entry) $value
  522.     set data(-selection) $value
  523.  
  524.     if {$data(-selectmode) == "browse"} {
  525.     if {$markSel} {
  526.         $data(w:entry) selection range 0 end
  527.     }
  528.     } else {
  529.     tixComboBox::SetValue $w $value
  530.     }
  531. }
  532.  
  533. proc tixComboBox::ClearListboxSelection {w} {
  534.     upvar #0 $w data
  535.  
  536.     $data(w:listbox) selection clear 0 end
  537. }
  538.  
  539. proc tixComboBox::UpdateListboxSelection {w index} {
  540.     upvar #0 $w data
  541.  
  542.     $data(w:listbox) selection clear 0 end
  543.  
  544.     if {$index != {}} {
  545.     $data(w:listbox) selection set $index
  546.     $data(w:listbox) selection anchor $index
  547.     }
  548. }
  549.  
  550. #----------------------------------------------------------------------
  551. #                   E V E N T   B I N D I N G S
  552. #----------------------------------------------------------------------
  553.  
  554. # The combobox issues a grab after it pops up the listbox. This procedure
  555. # will be called if the Mouse Button 1 is released outside of the listbox,
  556. # which means the user chooses no value.
  557. #
  558. # In this case, just pop down the listbox and restore the combox's
  559. # original value.
  560. #
  561. proc tixComboBox::BtnDown {w} {
  562.     upvar #0 $w data
  563.  
  564.     if {$data(-state) == "disabled"} {
  565.     return
  566.     }
  567.  
  568.     if {$data(-dropdown)} {
  569.     if {$data(popped) == 0} {
  570.         tixComboBox::PopupShell $w
  571.         set data(buttonHack) 1
  572.     } else {
  573.         tixComboBox::RestoreValue $w
  574.         tixComboBox::PopdownShell $w
  575.         catch {
  576.         unset data(buttonHack)
  577.         }
  578.     }
  579.     }
  580. }
  581.  
  582. proc tixComboBox::CalcelXX {w} {
  583.     upvar #0 $w data
  584.  
  585.     if {$data(-dropdown) && $data(popped)} {
  586.     tixComboBox::RestoreValue $w
  587.     tixComboBox::PopdownShell $w
  588.     }
  589. }
  590.  
  591. #----------------------------------------
  592. #  Handle events inside the entry box
  593. #----------------------------------------
  594. proc tixComboBox::EntButton1 {w} {
  595.     upvar #0 $w data
  596.  
  597.     if {$data(-state) == "disabled"} {
  598.     return
  599.     }
  600.  
  601.     if {$data(-dropdown) && !$data(-editable)} {
  602.     if {$data(popped)} {
  603.         tixComboBox::RestoreValue $w
  604.         tixComboBox::PopdownShell $w
  605.     } else {
  606.         tixComboBox::PopupShell $w
  607.     }
  608.     }
  609. }
  610.  
  611. proc tixComboBox::EntDouble {w} {
  612.     upvar #0 $w data
  613.  
  614.     if {$data(-state) == "disabled"} {
  615.     return
  616.     }
  617.  
  618.     if {$data(-editable)} {
  619.     $data(w:entry) select from 0
  620.     $data(w:entry) select to end
  621.     }
  622. }
  623.  
  624. # Handles the direction keys
  625. #
  626. proc tixComboBox::EntDirKey {w dir} {
  627.     upvar #0 $w data
  628.  
  629.     if {$data(-state) == "disabled"} {
  630.     return
  631.     }
  632.  
  633.     if {$data(-dropdown) && $data(popped) == 0} {
  634.     tixComboBox::PopupShell $w
  635.     }
  636.  
  637.     if {[$data(w:listbox) curselection] == {}} {
  638.     if {$data(curIndex) != {}} {
  639.         set index $data(curIndex)
  640.     } else {
  641.         set index 0
  642.     }
  643.  
  644.     $data(w:listbox) activate $index
  645.     $data(w:listbox) selection clear 0 end
  646.     $data(w:listbox) selection set $index
  647.     $data(w:listbox) see $index
  648.     return
  649.     }
  650.  
  651.     case $dir {
  652.     "up" {
  653.         tkListboxUpDown $data(w:listbox) -1
  654.     }
  655.     "down" {
  656.         tkListboxUpDown $data(w:listbox)  1
  657.     }
  658.     "pageup" {
  659.         $data(w:listbox) yview scroll -1 pages
  660.     }
  661.     "pagedown" {
  662.         $data(w:listbox) yview scroll  1 pages
  663.     }
  664.     }
  665. }
  666.  
  667. proc tixComboBox::EntInvoke {w forced} {
  668.     upvar #0 $w data
  669.  
  670.     if {!$forced && $data(-selection) == $data(-value)} {
  671.     return
  672.     }
  673.  
  674.     if {$data(-state) == "disabled"} {
  675.     return
  676.     }
  677.  
  678.     if {$data(-dropdown)  && $data(popped)} {
  679.     tixComboBox::PopdownShell $w
  680.     }
  681.  
  682.     if {[$data(w:listbox) curselection] == {}} {
  683.     set data(curIndex) {}
  684.     } else {
  685.     set data(curIndex) [tixComboBox::LbIndex $w]
  686.     }
  687.  
  688.     tixComboBox::SetValue $w [$data(w:entry) get]
  689.     $data(w:listbox) selection clear 0 end
  690.  
  691.     if {$data(-history)} {
  692.     tixComboBox::addhistory $w $data(-value)
  693.     set data(curIndex) 0
  694.     }
  695.     tixComboBox::BlinkEntry $w
  696. }
  697.  
  698. proc tixComboBox::Invoke {w} {
  699.     upvar #0 $w data
  700.  
  701.     if {$data(-state) == "disabled"} {
  702.     return
  703.     }
  704.  
  705.     if {$data(-dropdown)  && $data(popped)} {
  706.     tixComboBox::PopdownShell $w
  707.     }
  708.  
  709.     tixComboBox::BlinkEntry $w
  710.  
  711.     if {$data(-history)} {
  712.     tixComboBox::addhistory $w $data(-value)
  713.     }
  714. }
  715.  
  716. proc tixComboBox::EntKeyPress {w} {
  717.     upvar #0 $w data
  718.  
  719.     if {$data(-editable)} {
  720.     tixComboBox::ClearListboxSelection $w
  721.  
  722.     if {$data(-selectmode) == "browse"} {
  723.         set data(-selection) [$data(w:entry) get]
  724.     } else {
  725.         set data(-selection) [$data(w:entry) get]
  726.         tixComboBox::SetValue $w [$data(w:entry) get]
  727.     }
  728.     }
  729. }
  730.  
  731. #----------------------------------------------------------------------
  732. # General functions
  733. #
  734. #----------------------------------------------------------------------
  735. proc tixComboBox::EscKey {w} {
  736.     upvar #0 $w data
  737.  
  738.     case $data(-selectmode) {
  739.     browse {
  740.         tixSetEntry $data(w:entry) $data(-value)
  741.         set data(-selection) $data(-value)
  742.         tixComboBox::ClearListboxSelection $w
  743.     }
  744.     immediate {
  745.         tixSetEntry $data(w:entry) $data(-value)
  746.         tixComboBox::ClearListboxSelection $w
  747.     }
  748.     }
  749.  
  750.     if {$data(popped)} {
  751.     tixComboBox::PopdownShell $w
  752.     }
  753. }
  754.  
  755. # Make the entry blink when the user selects a choice
  756. #
  757. proc tixComboBox::BlinkEntry {w} {
  758.     upvar #0 $w data
  759.  
  760.     set old_bg [$data(w:entry) cget -bg]
  761.     set old_fg [$data(w:entry) cget -fg]
  762.  
  763.     $data(w:entry) config -fg $old_bg
  764.     $data(w:entry) config -bg $old_fg
  765.  
  766.     if {![info exists data(entryBlacken)]} {
  767.     set data(entryBlacken) 1
  768.     after 50 tixComboBox::RestoreEntry $w [list $old_bg] [list $old_fg]
  769.     }
  770. }
  771.  
  772. proc tixComboBox::RestoreEntry {w old_bg old_fg} {
  773.     upvar #0 $w data
  774.  
  775.     if {[info exists data(w:entry)] && [winfo exists $data(w:entry)]} {
  776.     $data(w:entry) config -fg $old_fg
  777.     $data(w:entry) config -bg $old_bg
  778.     }
  779.  
  780.     if [info exists data(entryBlacken)] {
  781.     unset data(entryBlacken)
  782.     }
  783. }
  784.  
  785. #----------------------------------------
  786. #  Handle events inside the list box
  787. #----------------------------------------
  788.  
  789. proc tixComboBox::LbIndex {w {flag {}}} {
  790.     upvar #0 $w data
  791.  
  792.     set sel [lindex [$data(w:listbox) curselection] 0]
  793.     if {$sel != {}} {
  794.     return $sel
  795.     } else {
  796.     if {$flag == "emptyOK"} {
  797.         return {}
  798.     } else {
  799.         return 0
  800.     }
  801.     }
  802. }
  803.  
  804. proc tixComboBox::LbBrowse {w} {
  805.     upvar #0 $w data
  806.  
  807.     if {$data(fakeBrowse)} {
  808.     set data(fakeBrowse) 0
  809.     return
  810.     }
  811.  
  812.     set index [tixComboBox::LbIndex $w emptyOK]
  813.  
  814.     if {$index >= 0} {
  815.     if {[focus -lastfor $data(w:entry)] != $data(w:entry) &&
  816.         [focus -lastfor $data(w:entry)] != $data(w:listbox)} {
  817.         focus $data(w:entry)
  818.     }
  819.  
  820.     set string [$data(w:listbox) get $index] 
  821.     tixComboBox::SetSelection $w $string
  822.  
  823.     tixComboBox::UpdateListboxSelection $w $index
  824.     
  825.     if {$data(-browsecmd) != {}} {
  826.         eval $data(-browsecmd) [list [$data(w:entry) get]]
  827.     }
  828.     }
  829. }
  830.  
  831. proc tixComboBox::LbChoose {w x y} {
  832.     upvar #0 $w data
  833.  
  834.     if {$x < 0 || $x > [winfo width  $data(w:listbox)] ||
  835.     $y < 0 || $y > [winfo height $data(w:listbox)]} {
  836.  
  837.     tixComboBox::EscKey $w
  838.     return
  839.     }
  840.  
  841.     tixComboBox::LbCommand $w
  842. }
  843.  
  844. proc tixComboBox::LbCommand {w} {
  845.     upvar #0 $w data
  846.  
  847.     set index [tixComboBox::LbIndex $w]
  848.     if {$index >= 0} {
  849.     set data(curIndex) $index
  850.         if {$data(-dropdown) == "true"  && $data(popped)} {
  851.         tixComboBox::PopdownShell $w
  852.         }
  853.     tixComboBox::SetValue $w [$data(w:listbox) get $index]
  854.     }
  855.  
  856.     tixComboBox::Invoke $w
  857.     set data(fakeBrowse) 1
  858. }
  859.  
  860. #----------------------------------------------------------------------
  861. # Internal commands
  862. #----------------------------------------------------------------------
  863. proc tixComboBox::ClearEntry {w} {
  864.     upvar #0 $w data
  865.  
  866.     $data(w:entry) delete 0 end
  867. }
  868.  
  869. proc tixComboBox::RestoreValue {w} {
  870.     upvar #0 $w data
  871.  
  872.     tixSetEntry $data(w:entry) $data(-value)
  873.     $data(w:entry) selection clear
  874. }
  875.  
  876. #--------------------------------------------------
  877. #        Popping up list shell
  878. #--------------------------------------------------
  879.  
  880. # Calculating the geometry of the combo box
  881. #
  882. #
  883. proc tixComboBox::PopupShell {w} {
  884.     upvar #0 $w data
  885.  
  886.     if {!$data(-dropdown)} {
  887.     return
  888.     }
  889.  
  890.     if {![winfo ismapped $data(w:root)]} {
  891.     return
  892.     }
  893.  
  894.     if {$data(-listcmd) != {}} {
  895.     # This option allows the user to fill in the listbox on demand
  896.     #
  897.     eval $data(-listcmd)
  898.     }
  899.  
  900.     # calculate the size
  901.     set  y [winfo rooty $data(w:entry)]
  902.     incr y [winfo height $data(w:entry)]
  903.     incr y 3
  904.  
  905.     set bd [$data(w:shell) cget -bd]
  906.     incr bd [$data(w:shell) cget -highlightthickness]
  907.     set height [expr [winfo reqheight $data(w:slistbox)] + 2*$bd]
  908.  
  909.     set x1 [winfo rootx $data(w:entry)]
  910.     if {$data(-listwidth) == {}} {
  911.     set x2  [winfo rootx $data(w:arrow)]
  912.     incr x2 [winfo width $data(w:arrow)]
  913.     set width  [expr "$x2 - $x1"]
  914.     } else {
  915.     set width $data(-listwidth)
  916.     set x2 [expr $x1 + $width]
  917.     }
  918.  
  919.     set reqwidth [winfo reqwidth $data(w:shell)]
  920.     if {$reqwidth < $width} {
  921.     set reqwidth $width
  922.     } else {
  923.     if {$reqwidth > [expr $width *3]} {
  924.         set reqwidth [expr $width *3]
  925.     }
  926.     if {$reqwidth > [winfo vrootwidth .]} {
  927.         set reqwidth [winfo vrootwidth .]
  928.     }
  929.     }
  930.     set width $reqwidth
  931.  
  932.     # If the listbox is too far right, pull it back to the left
  933.     #
  934.     set scrwidth [winfo vrootwidth .]
  935.     if {$x2 > $scrwidth} {
  936.     set x1 [expr $scrwidth - $width]
  937.     }
  938.  
  939.     # If the listbox is too far left, pull it back to the right
  940.     #
  941.     if {$x1 < 0} {
  942.     set x1 0
  943.     }
  944.  
  945.     # If the listbox is below bottom of screen, put it upwards
  946.     #
  947.     set scrheight [winfo vrootheight .]
  948.     set bottom [expr $y+$height]
  949.     if {$bottom > $scrheight} {
  950.     set y [expr $y-$height-[winfo height $data(w:entry)]-5]
  951.     }
  952.  
  953.     # OK , popup the shell
  954.     #
  955.     wm geometry $data(w:shell) $reqwidth\x$height+$x1+$y
  956.     wm deiconify $data(w:shell)
  957.     raise $data(w:shell)
  958.     focus $data(w:entry)
  959.     set data(popped) 1
  960.  
  961.     # Grab the server so that user cannot move the windows around
  962.     #
  963.     $data(rootCmd) config -cursor arrow
  964.     catch {
  965.     # We catch here because grab may fail under a lot of circumstances
  966.     # Just don't want to break the code ...
  967.     case $data(-grab) {
  968.         global {
  969.         tixPushGrab -global $data(w:root)
  970.         }
  971.         local {
  972.         tixPushGrab $data(w:root)
  973.         }
  974.     }
  975.     }
  976. }
  977.  
  978. proc tixComboBox::popdown {w} {
  979.     tixComboBox::PopdownShell $w
  980. }
  981.  
  982. proc tixComboBox::PopdownShell {w} {
  983.     upvar #0 $w data
  984.  
  985.     if {$data(-dropdown) && $data(popped)} {
  986.     wm withdraw $data(w:shell)
  987.     $data(rootCmd) config -cursor {}
  988.     tixPopGrab
  989.     set data(popped) 0
  990.     }
  991. }
  992.  
  993. proc tixComboBox::TraceEntryVar {w args} {
  994.     upvar #0 $w data
  995.     global $w::combo
  996.  
  997.     set value [set $w::combo]
  998.     set data(-selection) $value
  999.  
  1000.     set i [$data(w:listbox) curselection]
  1001.     if {$i != {}} {
  1002.     if {[$data(w:listbox) get $i] != $value} {
  1003.         $data(w:listbox) select clear 0 end
  1004.     }
  1005.     }
  1006. }
  1007.  
  1008. # Because we do a grab, the following events sequence will make things ugly:
  1009. #
  1010. # (1) Press arrow
  1011. # (2) Move mouse out of arrow button
  1012. # (3) Release mouse button
  1013. #
  1014. # The arrow button will remain depressed (how ugly!). The following code
  1015. # fixes that
  1016. #
  1017. proc tixComboBox::ButtonHack {w} {
  1018.     upvar #0 $w data
  1019.  
  1020.     if [info exists data(buttonHack)] {
  1021.     catch {
  1022.         tkButtonUp $data(w:arrow)
  1023.     }
  1024.     }
  1025. }
  1026. #----------------------------------------------------------------------
  1027. #         Alignment
  1028. #----------------------------------------------------------------------
  1029. # The following two routines can emulate a "right align mode" for the
  1030. # entry in the combo box.
  1031.  
  1032. proc tixComboBox::EntryAlignEnd {w} {
  1033.     upvar #0 $w data
  1034.     $data(w:entry) xview end
  1035. }
  1036.  
  1037.  
  1038. proc tixComboBox::Destructor {w} {
  1039.     upvar #0 $w data
  1040.  
  1041.     tixUnsetMegaWidget $data(w:entry)
  1042.     tixVariable:DeleteVariable $w
  1043.  
  1044.     catch {
  1045.     global $w::combo
  1046.     trace vdelete $w::combo w "tixComboBox::TraceEntryVar $w"
  1047.     unset $w::combo
  1048.     }
  1049.     
  1050.     # Chain this to the superclass
  1051.     #
  1052.     tixChainMethod $w Destructor
  1053. }
  1054.